using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using WpfWordsLearner.Helper;

namespace WpfWordsLearner.ViewModels
{
	public class TestViewModel : BaseViewModel
	{
		public System.Windows.Threading.Dispatcher Dispatcher
		{
			get;
			set;
		}

		private Model.TestSettingsModel m_testSetting = null;
		private Queue<Model.TestWordModel> m_answers = null;

		public TestViewModel()
		{
			m_answers = new Queue<Model.TestWordModel>();
			Result = new List<Model.TestWordModel>();
			m_answers.Enqueue(new Model.TestWordModel() { Word = new Model.WordsModel() { EnglishWord = "Hello", Translate = "Привет" } });
			UseAnswers = false;

			PossibleAnswers = new System.Collections.ObjectModel.ObservableCollection<string>();
		}

		private List<Model.TestWordModel> m_resultOfTest = null;
		public List<Model.TestWordModel> Result
		{
			get { return m_resultOfTest; }
			set
			{
				m_resultOfTest = value;
				OnPropertyChanged(() => Result);
			}
		}

		private bool m_isNext = false;
		public bool IsNextAvaliable
		{
			get
			{
				return m_isNext;
			}
			set
			{
				m_isNext = value;
				OnPropertyChanged(() => IsNextAvaliable);
			}
		}

		private bool m_isResultAvaliable = false;
		public bool IsResultAvaliable
		{
			get
			{
				return m_isResultAvaliable;
			}
			set
			{
				m_isResultAvaliable = value;
				OnPropertyChanged(() => IsResultAvaliable);
			}
		}

		private Model.TestWordModel m_answer = null;
		public Model.TestWordModel CurrentAnswer
		{
			get { return m_answer; }
			set
			{
				m_answer = value;
				OnPropertyChanged(() => CurrentAnswer);
			}
		}

		private bool m_useAnswers;
		public bool UseAnswers
		{
			get { return m_useAnswers; }
			set { m_useAnswers = value; OnPropertyChanged(() => UseAnswers); }
		}

		private System.Collections.ObjectModel.ObservableCollection<string> m_curAnsw;
		public System.Collections.ObjectModel.ObservableCollection<string> PossibleAnswers
		{
			get { return m_curAnsw; }
			set { m_curAnsw = value; OnPropertyChanged(() => PossibleAnswers); }
		}

		public void SetTestSettings(Model.TestSettingsModel settings)
		{
			if (settings == null)
				throw new ArgumentNullException("settings");

			this.m_testSetting = settings;
			m_answers.Clear();

			TestGenerator generator = new TestGenerator(m_testSetting.WordsCount);
			foreach (var item in generator.GenerateTestSet())
			{
				m_answers.Enqueue(new Model.TestWordModel() { Word = item.Word, Answer = "Enter answer here...", IsCorrect = false });
			}

			if (m_answers.Count > 0)
			{
				IsNextAvaliable = true;
				IsResultAvaliable = false;
				CurrentAnswer = m_answers.Dequeue();

				PossibleAnswers.Clear();
				PossibleAnswers.Add(CurrentAnswer.Word.Translate);
				Random r = new Random();
				for (int i = 0; i < 2; i++)
				{
					int result = r.Next(1, m_answers.Count);
					PossibleAnswers.Add(m_answers.ElementAt(result).Word.Translate);
				}
			}
		}

		public void SetTestSettings(List<Model.LearnItem> items)
		{
			if (items == null)
				throw new ArgumentNullException("items");

			m_answers.Clear();
			UseAnswers = false;
			foreach (var item in items)
			{
				Model.WordsModel model = new Model.WordsModel();
				model.EnglishWord = item.Word;
				model.Translate = item.Translate;
				m_answers.Enqueue(new Model.TestWordModel() { Word = model, Answer = "Enter answer here...", IsCorrect = false });
			}

			if (m_answers.Count > 0)
			{
				IsNextAvaliable = true;
				IsResultAvaliable = false;
				CurrentAnswer = m_answers.Dequeue();

				PossibleAnswers.Clear();
				PossibleAnswers.Add(CurrentAnswer.Word.Translate);
				Random r = new Random();
				for (int i = 0; i < 2; i++)
				{
					int result = r.Next(1, m_answers.Count);
					PossibleAnswers.Add(m_answers.ElementAt(result).Word.Translate);
				}
			}
		}

		public ICommand NextCommand { get { return new BaseCommand(NextClick, new Func<bool>(CanNextExecute)); } }
		private void NextClick()
		{
			if (CurrentAnswer != null && !string.IsNullOrEmpty(CurrentAnswer.Answer))
			{
				if (Check())
				{
					CurrentAnswer.IsCorrect = true;
				}
				Result.Add(CurrentAnswer);
			}
			if (m_answers.Count > 0)
			{
				CurrentAnswer = m_answers.Dequeue();

				PossibleAnswers.Clear();
				PossibleAnswers.Add(CurrentAnswer.Word.Translate);
				Random rand = new Random();
				for (int i = 0; i < 2; i++)
				{
					if (m_answers.Count > 2)
					{
						int result = rand.Next(1, m_answers.Count);
						PossibleAnswers.Add(m_answers.ElementAt(result).Word.Translate);
					}
					else
					{
						int result = rand.Next(1, Result.Count);
						PossibleAnswers.Add(Result.ElementAt(result).Word.Translate);
					}
				}
				PossibleAnswers.ToList().Sort();
			}
		}

		private bool Check()
		{
			string[] original = CurrentAnswer.Word.Translate.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			string[] answers = CurrentAnswer.Answer.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			bool found = false;
			foreach (string answer in answers)
			{
				foreach (string orig in original)
				{
					if (string.Compare(answer.Trim(), orig.Trim(), StringComparison.OrdinalIgnoreCase) == 0)
					{ found = true; break; }
				}
				if (found)
					break;
			}

			original = null;
			answers = null;
			return found;
		}

		private bool CanNextExecute()
		{
			bool result = (m_answers != null && m_answers.Count > 0);

			if (m_testSetting != null && Result.Count != m_testSetting.WordsCount && m_answers.Count == 0)
				NextClick();

			IsResultAvaliable = !result;
			IsNextAvaliable = result;

			return result;
		}

		public ICommand ResultCommand { get { return new BaseCommand(ResultClick); } }
		private void ResultClick()
		{
			System.Windows.Window wind = App.Current.Windows.Cast<System.Windows.Window>().SingleOrDefault(x => x.IsActive);
			if (wind != null)
				wind.Close();

			Views.ResultView result = new Views.ResultView();
			result.dgrResults.DataContext = this;
			result.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
			result.Topmost = true;
			result.ShowInTaskbar = false;
			result.Owner = App.Current.MainWindow;
			result.Show();
		}

		public ICommand VoiceCommand { get { return new BaseCommand(voice); } }
		private void voice()
		{
			if (this.Dispatcher == null)
				this.Dispatcher = CurrentAnswer.Dispatcher;

			System.Threading.Tasks.Task.Factory.StartNew(new Action(() =>
			{
				using (VoiceManager2 manager = new VoiceManager2())
				using (ServiceReferenceTranslater.TranslateServiceClient client = new ServiceReferenceTranslater.TranslateServiceClient())
				using (DAO.WordsDaoPlain plain = new DAO.WordsDaoPlain(App.pathToDB))
				{
					string wordToVoiced = null;
					this.Dispatcher.BeginInvoke(new Action(() =>
							wordToVoiced = CurrentAnswer.Word.EnglishWord
						), System.Windows.Threading.DispatcherPriority.Normal).Wait(TimeSpan.FromMilliseconds(200));

					if (plain.IsWordVoiced(wordToVoiced))
					{
						byte[] data = plain.GetVoiceForWord(wordToVoiced);
						if (data != null)
						{
							System.IO.Stream sr = new System.IO.MemoryStream(data);
							manager.Play(sr);
							System.Threading.Thread.Sleep(500);
							sr.Dispose();
						}
					}
					else
					{
						var req = new ServiceReferenceTranslater.VoiceRequest();
						req.ToLanguage = "en";
						req.OriginalText = wordToVoiced;
						ServiceReferenceTranslater.VoiceResponse response = null;
						try
						{
							response = client.GetVoice(req);
							if (response != null && response.Data != null)
							{
								plain.AddVoicedWord(req.OriginalText, response.Data);
								System.IO.Stream sr = new System.IO.MemoryStream(response.Data);
								manager.Play(sr);
								System.Threading.Thread.Sleep(500);
								sr.Dispose();
							}
						}
						catch (System.ServiceModel.FaultException<ServiceReferenceTranslater.VoiceFault> ex)
						{
							App.Log.Error(WpfWordsLearner.Properties.Resources.failVoice, ex);
						}
					}
				}
			})).ContinueWith(prevTask =>
			{
				App.Log.Error(WpfWordsLearner.Properties.Resources.failVoice, prevTask.Exception.Flatten());
				prevTask.Dispose();
			}, System.Threading.Tasks.TaskContinuationOptions.NotOnRanToCompletion);
		}
	}
}
